package copyengine.dataLayer.rpc.moudle.request
{
	import copyengine.utils.GeneralUtils;
	import copyengine.utils.debug.CELog;
	import copyengine.utils.tick.GlobalTick;

	import flash.events.Event;
	import flash.events.NetStatusEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.TimerEvent;
	import flash.net.NetConnection;
	import flash.net.ObjectEncoding;
	import flash.net.Responder;
	import flash.utils.Timer;

	public final class CENetConnectionWrapper implements ICERequestWrapper
	{
		private var requestManger:ICERpcRequestModule;

		private var requestURL:String;
		private var requestData:Object;

		private var retryTime:int;
		private var timeoutTimer:Timer;

		private var requestNetConnection:NetConnection;

		private var isReTryInNextTick:Boolean = false;

		public function CENetConnectionWrapper()
		{
		}

		public function sendRequest(_requestManger:ICERpcRequestModule,
									_data:*,
									_requestURL:String,
									_retryTime:int,
									_timeoutTime:int):void
		{
			requestManger = _requestManger;
			requestURL = _requestURL;
			requestData = _data;
			retryTime = _retryTime;
			timeoutTimer = new Timer(_timeoutTime);
			startSendRequest();
		}

		private function startSendRequest():void
		{
			var respond:Responder = new Responder(onSucceed, onError);

			requestNetConnection = new NetConnection();
			requestNetConnection.objectEncoding = ObjectEncoding.AMF3;

			timeoutTimer.start();

			addListener();

			requestNetConnection.connect(requestURL);
			requestNetConnection.call("Index.Main", respond, requestData);

			for each (var data:Object in requestData.data)
			{
				CELog.log("RPC: " + data.method);
			}
		}

		public function dispose():void
		{
			removeListener();
			requestNetConnection.close();
			timeoutTimer.stop();
			GlobalTick.instance.removeTickNodeByFunction(doTryToReSend);
			requestNetConnection = null;
			timeoutTimer = null;
			requestData = null;
			requestManger = null;
		}

		private function addListener():void
		{
			GeneralUtils.addTargetEventListener(timeoutTimer, TimerEvent.TIMER_COMPLETE, onTimeout);
			GeneralUtils.addTargetEventListener(requestNetConnection, NetStatusEvent.NET_STATUS, onError);
			GeneralUtils.addTargetEventListener(requestNetConnection, SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
		}

		private function removeListener():void
		{
			GeneralUtils.removeTargetEventListener(timeoutTimer, TimerEvent.TIMER_COMPLETE, onTimeout);
			GeneralUtils.removeTargetEventListener(requestNetConnection, NetStatusEvent.NET_STATUS, onError);
			GeneralUtils.removeTargetEventListener(requestNetConnection, SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
		}


		private function onSucceed(_result:Object):void
		{
			requestManger.receiveServerResponse(_result, this);
		}

		private function onError(... args):void
		{
			CELog.err((args[0] as NetStatusEvent).info.code);
			tryToReSend();
		}

		private function onSecurityError(e:SecurityErrorEvent):void
		{
			CELog.err("CENetConnectionWrapper NeConnection SecurityError :\n" + e.toString());
		}

		private function onTimeout(e:Event):void
		{
			CELog.err("Timeout");
			tryToReSend();
		}


		private function tryToReSend():void
		{
			if (!isReTryInNextTick)
			{
				isReTryInNextTick = true;
				GlobalTick.instance.callLaterAfterTickCount(doTryToReSend);
			}
		}

		private function doTryToReSend():void
		{
			isReTryInNextTick = false;
			retryTime--;
			if (retryTime > 0)
			{
				CELog.err("Sending Data Failed Start Retry , Retry Remain Time : " + retryTime);
				resetPreRequest();
				startSendRequest();
			}
			else
			{
				requestManger.failedToRequest(this);
			}
		}

		private function resetPreRequest():void
		{
			//先要清除Listener监听才能调用requestNetConnection.close()方法
			//因为requestNetConnection.close()方法也会触发NetStatusEvent.NET_STATUS Event
			removeListener();
			requestNetConnection.close();
			requestNetConnection = null;
			timeoutTimer.reset();
		}

	}
}
